from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import List, Optional
from datetime import datetime
from ..db import get_db
from .. import models, schemas
from ..security import get_current_user

router = APIRouter()

@router.post("/", response_model=schemas.IssueOut)
def create_issue(payload: schemas.IssueCreate, db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = models.Issue(
        title=payload.title,
        description=payload.description,
        summary=payload.summary,
        status=payload.status or "todo",
        priority=payload.priority or "P2",
        importance=payload.importance,
        urgency=payload.urgency,
        deadline=payload.deadline,
        group_id=payload.group_id,
        owner_id=current.id,
    )
    db.add(issue)
    db.flush()
    if payload.steps:
        for s in payload.steps:
            db.add(models.IssueStep(issue_id=issue.id, content=s.content, done=s.done))
    # assign folder: ensure single link
    db.query(models.IssueFolder).filter(models.IssueFolder.issue_id == issue.id).delete()
    if payload.folder_id is not None:
        db.add(models.IssueFolder(issue_id=issue.id, folder_id=payload.folder_id))
    else:
        # put into Inbox '收集箱' at root for this user (lazy create)
        inbox = db.query(models.Folder).filter(models.Folder.owner_id == current.id, models.Folder.name == "收集箱").first()
        if not inbox:
            next_order = 0
            # place at top by using order 0; others will shift as needed on reorders
            inbox = models.Folder(name="收集箱", parent_id=None, owner_id=current.id, order=next_order)
            db.add(inbox)
            db.flush()
        db.add(models.IssueFolder(issue_id=issue.id, folder_id=inbox.id))
    # create initial summary version if provided
    if payload.summary:
        db.add(models.IssueSummary(issue_id=issue.id, content=payload.summary))
    db.commit()
    db.refresh(issue)
    return issue

# Summary history endpoints
@router.get("/{issue_id}/summaries", response_model=list[schemas.IssueSummaryOut])
def list_summaries(issue_id: int, db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = db.query(models.Issue).filter(models.Issue.id == issue_id, models.Issue.owner_id == current.id).first()
    if not issue:
        raise HTTPException(status_code=404, detail="Issue not found")
    return issue.summaries

@router.post("/{issue_id}/summaries", response_model=schemas.IssueSummaryOut)
def add_summary(issue_id: int, content: str = Query(..., description="HTML content of summary"), db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = db.query(models.Issue).filter(models.Issue.id == issue_id, models.Issue.owner_id == current.id).first()
    if not issue:
        raise HTTPException(status_code=404, detail="Issue not found")
    s = models.IssueSummary(issue_id=issue.id, content=content)
    issue.summary = content
    db.add(s)
    db.commit()
    db.refresh(s)
    return s

# alias without trailing slash to avoid 307 redirect
@router.post("", response_model=schemas.IssueOut)
def create_issue_noslash(payload: schemas.IssueCreate, db: Session = Depends(get_db), current=Depends(get_current_user)):
    return create_issue(payload, db, current)

@router.post("/{issue_id}/to-knowledge")
def issue_to_knowledge(issue_id: int, db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = db.query(models.Issue).filter(models.Issue.id == issue_id, models.Issue.owner_id == current.id).first()
    if not issue:
        raise HTTPException(status_code=404, detail="Issue not found")
    k = models.Knowledge(title=issue.title, summary=issue.description, body=issue.description or '', owner_id=current.id)
    db.add(k)
    db.flush()
    db.add(models.IssueKnowledgeLink(issue_id=issue.id, knowledge_id=k.id))
    db.commit()
    return {"knowledge_id": k.id}

@router.get("/", response_model=List[schemas.IssueOut])
def list_issues(
    db: Session = Depends(get_db),
    current=Depends(get_current_user),
    status: Optional[str] = None,
    priority: Optional[str] = None,
    group_id: Optional[int] = None,
    folder_id: Optional[int] = None,
    include_desc: Optional[bool] = False,
):
    q = db.query(models.Issue)
    if folder_id is not None:
        if include_desc:
            # collect descendant folder ids for current user
            folders = db.query(models.Folder).filter(models.Folder.owner_id == current.id).all()
            child_map: dict[int | None, list[int]] = {}
            for f in folders:
                child_map.setdefault(f.parent_id, []).append(f.id)
            target_ids = {folder_id}
            stack = list(child_map.get(folder_id, []))
            while stack:
                fid = stack.pop()
                if fid in target_ids:
                    continue
                target_ids.add(fid)
                stack.extend(child_map.get(fid, []))
            q = q.join(models.IssueFolder, models.IssueFolder.issue_id == models.Issue.id).filter(models.IssueFolder.folder_id.in_(target_ids))
        else:
            q = q.join(models.IssueFolder, models.IssueFolder.issue_id == models.Issue.id).filter(models.IssueFolder.folder_id == folder_id)
    q = q.filter(models.Issue.owner_id == current.id)
    
    # Soft delete filter
    if status == 'trash':
        q = q.filter(models.Issue.is_deleted == True)
    else:
        q = q.filter(models.Issue.is_deleted == False)
        if status:
            q = q.filter(models.Issue.status == status)

    if priority:
        q = q.filter(models.Issue.priority == priority)
    if group_id:
        q = q.filter(models.Issue.group_id == group_id)
    return q.order_by(models.Issue.created_at.desc()).all()

# alias without trailing slash to avoid 307 redirect
@router.get("", response_model=List[schemas.IssueOut])
def list_issues_noslash(
    db: Session = Depends(get_db),
    current=Depends(get_current_user),
    status: Optional[str] = None,
    priority: Optional[str] = None,
    group_id: Optional[int] = None,
    folder_id: Optional[int] = None,
    include_desc: Optional[bool] = False,
):
    return list_issues(db, current, status, priority, group_id, folder_id, include_desc)

@router.get("/{issue_id}", response_model=schemas.IssueOut)
def get_issue(issue_id: int, db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = db.query(models.Issue).filter(models.Issue.id == issue_id, models.Issue.owner_id == current.id).first()
    if not issue:
        raise HTTPException(status_code=404, detail="Issue not found")
    link = db.query(models.IssueFolder).filter(models.IssueFolder.issue_id == issue.id).first()
    folder_id = link.folder_id if link else None
    # Build response with folder_id and summaries
    return {
        "id": issue.id,
        "title": issue.title,
        "description": issue.description,
        "summary": issue.summary,
        "status": issue.status,
        "priority": issue.priority,
        "importance": issue.importance,
        "urgency": issue.urgency,
        "deadline": issue.deadline,
        "folder_id": folder_id,
        "created_at": issue.created_at,
        "updated_at": issue.updated_at,
        "steps": issue.steps,
        "summaries": issue.summaries,
    }

@router.put("/{issue_id}", response_model=schemas.IssueOut)
def update_issue(issue_id: int, payload: schemas.IssueUpdate, db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = db.query(models.Issue).filter(models.Issue.id == issue_id, models.Issue.owner_id == current.id).first()
    if not issue:
        raise HTTPException(status_code=404, detail="Issue not found")
    data = payload.model_dump(exclude_unset=True)
    folder_id = data.pop("folder_id", None) if "folder_id" in data else None
    # if summary present, add a version record
    if "summary" in data:
        if data["summary"] is not None:
            db.add(models.IssueSummary(issue_id=issue.id, content=data["summary"]))
    for field, value in data.items():
        setattr(issue, field, value)
    if folder_id is not None:
        # replace link
        db.query(models.IssueFolder).filter(models.IssueFolder.issue_id == issue.id).delete()
        if folder_id:
            db.add(models.IssueFolder(issue_id=issue.id, folder_id=folder_id))
    db.commit()
    db.refresh(issue)
    return issue

@router.delete("/{issue_id}")
def delete_issue(issue_id: int, db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = db.query(models.Issue).filter(models.Issue.id == issue_id, models.Issue.owner_id == current.id).first()
    if not issue:
        raise HTTPException(status_code=404, detail="Issue not found")
    # Soft delete
    issue.is_deleted = True
    issue.deleted_at = datetime.utcnow()
    db.commit()
    return {"ok": True}

@router.post("/{issue_id}/restore")
def restore_issue(issue_id: int, db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = db.query(models.Issue).filter(models.Issue.id == issue_id, models.Issue.owner_id == current.id).first()
    if not issue:
        raise HTTPException(status_code=404, detail="Issue not found")
    issue.is_deleted = False
    issue.deleted_at = None
    db.commit()
    return {"ok": True}

@router.delete("/{issue_id}/hard")
def hard_delete_issue(issue_id: int, db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = db.query(models.Issue).filter(models.Issue.id == issue_id, models.Issue.owner_id == current.id).first()
    if not issue:
        raise HTTPException(status_code=404, detail="Issue not found")
    db.delete(issue)
    db.commit()
    return {"ok": True}

@router.delete("/trash/empty")
def empty_trash(db: Session = Depends(get_db), current=Depends(get_current_user)):
    db.query(models.Issue).filter(models.Issue.owner_id == current.id, models.Issue.is_deleted == True).delete()
    db.commit()
    return {"ok": True}

@router.post("/{issue_id}/steps", response_model=schemas.IssueOut)
def add_step(issue_id: int, step: schemas.IssueStepIn, db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = db.query(models.Issue).filter(models.Issue.id == issue_id, models.Issue.owner_id == current.id).first()
    if not issue:
        raise HTTPException(status_code=404, detail="Issue not found")
    db.add(models.IssueStep(issue_id=issue.id, content=step.content, done=step.done))
    db.commit()
    db.refresh(issue)
    return issue

@router.put("/{issue_id}/steps/{step_id}", response_model=schemas.IssueOut)
def update_step(issue_id: int, step_id: int, step: schemas.IssueStepIn, db: Session = Depends(get_db), current=Depends(get_current_user)):
    issue = db.query(models.Issue).filter(models.Issue.id == issue_id, models.Issue.owner_id == current.id).first()
    if not issue:
        raise HTTPException(status_code=404, detail="Issue not found")
    s = db.query(models.IssueStep).filter(models.IssueStep.id == step_id, models.IssueStep.issue_id == issue.id).first()
    if not s:
        raise HTTPException(status_code=404, detail="Step not found")
    s.content = step.content
    s.done = step.done
    db.commit()
    db.refresh(issue)
    return issue
